// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TransactionalDbContext.cs" company="emrecoskun.net">
//   ecblog.codeplex.com - emrecoskun.net
// </copyright>
// <summary>
//   The transactional Db context
// </summary>
// --------------------------------------------------------------------------------------------------------------------
 
namespace EcBlog.Data.Sql.Base
{
    using System;
    using System.Data.Common;
    using System.Data.Entity;
    using System.Transactions;

    /// <summary>
    /// The transactional Db context
    /// </summary>
    public abstract class TransactionalDbContext : DbContext
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TransactionalDbContext"/> class.
        /// </summary>
        /// <param name="connectionString">The connection string.</param>
        protected TransactionalDbContext(string connectionString)
            : base(connectionString)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TransactionalDbContext"/> class.
        /// </summary>
        /// <param name="connection">The connection.</param>
        protected TransactionalDbContext(DbConnection connection = null)
            : base(connection, true)
        {
            this.Configuration.ProxyCreationEnabled = false;
            this.Configuration.LazyLoadingEnabled = true;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TransactionalDbContext"/> class.
        /// </summary>
        protected TransactionalDbContext()
        {
            this.Configuration.ProxyCreationEnabled = false;
            this.Configuration.LazyLoadingEnabled = true;
        }

        /// <summary>
        /// The save changing event handler.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        public delegate void OnSaveChangingEventHandler(object sender, EventArgs e);

        /// <summary>
        /// The save changed event handler.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        public delegate void OnSaveChangedEventHandler(object sender, EventArgs e);

        /// <summary>
        /// The save complated event handler.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        public delegate void OnSaveComplatedEventHandler(object sender, EventArgs e);

        /// <summary>
        /// Occurs when [on save changing].
        /// </summary>
        public event OnSaveChangingEventHandler OnSaveChanging;

        /// <summary>
        /// Occurs when [on save changed].
        /// </summary>
        public event OnSaveChangedEventHandler OnSaveChanged;

        /// <summary>
        /// Occurs when [on save complated].
        /// </summary>
        public event OnSaveComplatedEventHandler OnSaveComplated;

        /// <summary>
        /// Saves all changes made in this context to the underlying database.
        /// </summary>
        /// <returns>
        /// The number of objects written to the underlying database.
        /// </returns>
        /// <exception cref="T:System.InvalidOperationException">Thrown if the context has been disposed.</exception>
        public override int SaveChanges()
        {
            int result;
            if (this.OnSaveChanging != null)
            {
                this.OnSaveChanging(this, new EventArgs());
            }

            using (var scope = new TransactionScope(TransactionScopeOption.Required))
            {
                result = base.SaveChanges();
                scope.Complete();
            }

            if (this.OnSaveChanged != null)
            {
                this.OnSaveChanged(this, new EventArgs());
            }

            // TODO: add if any changes exists
            using (var scope = new TransactionScope(TransactionScopeOption.Required))
            {
                base.SaveChanges();
                scope.Complete();
            }

            if (this.OnSaveComplated != null)
            {
                this.OnSaveComplated(this, new EventArgs());
            }

            this.OnSaveChanging = null;
            this.OnSaveChanged = null;
            this.OnSaveComplated = null;

            return result;
        }
    }
}